package com.briup.jdbc.conn;

import java.io.FileInputStream;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Date;
import java.util.Iterator;
import java.util.Properties;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.TimeUnit;

public class ConnectionImpl implements IConnection {

	// 存储连接的并发队列
	private static ArrayBlockingQueue<UpConnection> connQueue;

	// 表示并发队列中的边界默认值 20
	private static int defaultConnQueueMax = 20;

	// 已经创建并未关闭的连接数
	private static int alivedConnCount = 0;

	// 允许空闲的最大连接数,默认5
	private static int freeConnMax = 5;

	// 获取连接的超时时间，单位毫秒,默认2000
	private static int outTime = 2000;

	// 数据库驱动信息
	private static String driverName;
	// 数据库连接信息
	private static String url;
	// 用户名/数据库名
	private static String user;
	// 密码
	private static String password;
	// pojo类地址
	public static String pojo;

	// 空闲连接存活时间,33秒
	private static int freeAlivedTime = 1000 * 33; // 1000 * 6;

	// 连接回收线程执行周期,10秒
	private static int cycleThreadTime = 1000 * 10;// 1000 * 4;

	/**
	 * 解析配置文件，加载数据库连接信息，并加载驱动
	 */
	static {
		try {
			Properties connInfo = new Properties();
			connInfo.load(new FileInputStream("src/jdbc.properties"));
			driverName = connInfo.getProperty("driverName");
			url = connInfo.getProperty("url");
			user = connInfo.getProperty("user");
			password = connInfo.getProperty("password");
			pojo = connInfo.getProperty("pojo");
			if (connInfo.containsKey(defaultConnQueueMax)) {
				defaultConnQueueMax = Integer.parseInt((String) connInfo.get("defaultConnQueueMax"));
			}
			if (connInfo.containsKey(freeConnMax)) {
				int temp = Integer.parseInt((String) connInfo.get("freeConnMax"));
				freeConnMax = temp > defaultConnQueueMax ? defaultConnQueueMax : temp;
			}
			if (connInfo.containsKey(outTime)) {
				outTime = Integer.parseInt((String) connInfo.get("outTime"));
			}

			// 创建并发队列
			connQueue = new ArrayBlockingQueue<UpConnection>(defaultConnQueueMax);
			// 1）注册驱动
			Class.forName(driverName);

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public ConnectionImpl() {
		super();
		Thread thread = new Thread(new CycleCheckConnQueue());
		thread.setDaemon(true);
		thread.start();
	}

	@Override
	public synchronized UpConnection getConn() throws SQLException, InterruptedException {
		UpConnection upConn = connQueue.poll();
		if (upConn == null && alivedConnCount >= defaultConnQueueMax) {
			upConn = connQueue.poll(outTime, TimeUnit.MILLISECONDS);
		}
		if (upConn == null && alivedConnCount < defaultConnQueueMax) {
			upConn = new UpConnection();
			Connection conn = DriverManager.getConnection(url, user, password);
			upConn.conn = conn;
			alivedConnCount++;
		}
		return upConn;
	}

	@Override
	public synchronized void close(UpConnection upConn) throws InterruptedException, SQLException {
		upConn.conn.commit();
		if (connQueue.size() < defaultConnQueueMax) {
//			System.out.println("=============================连接放回并发队列============");
			connQueue.put(upConn);
		} else {
			upConn.conn.close();
		}
	}

	@Override
	public void commit(UpConnection upConn) throws SQLException {
		upConn.conn.commit();
	}

	@Override
	public void rollback(UpConnection upConn) throws SQLException {
		upConn.conn.rollback();
	}

	/**
	 * 周期性检测连接池，清除2分钟内没有使用的线程，周期为1分钟
	 * 
	 * @author 8852LDS
	 * @date 2019年9月21日
	 */
	class CycleCheckConnQueue implements Runnable {

		@Override
		public void run() {
			while (true) {

				if (connQueue.size() > freeConnMax) {

					for (UpConnection upConn : connQueue) {
						if (upConn.recentUsedTime != null
								&& (System.currentTimeMillis() - upConn.recentUsedTime.getTime()) > freeAlivedTime) {
							connQueue.remove(upConn);
							try {
								upConn.conn.close();
							} catch (SQLException e) {
								e.printStackTrace();
							}
							alivedConnCount--;
//							System.out.println(">>清理一个连接》》");
						}
						if (connQueue.size() <= freeConnMax) {
							break;
						}
					}

				}
//				System.out.println("################回收长时间未使用空闲连接##################");
//				System.out.println("################最大连接数：" + defaultConnQueueMax + " ########################");
//				System.out.println("################当前空闲数：" + connQueue.size() + " ########################");
//				System.out.println("################当前存活数：" + alivedConnCount + " ########################");
//				System.out.println("###################################################");
				try {
					Thread.sleep(cycleThreadTime);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}

			}
		}

	}

}
